const parse = require('@babel/parser').parse;
const fs = require('fs');
const path = require('path');

function getFileContent(abPath) {
  if (!fs.existsSync(abPath)) {
    if (fs.existsSync(abPath + '.js')) {
      abPath += '.js';
    } else if (fs.existsSync(abPath + '/index.js')) {
      abPath += '/index.js';
    }
  }
  let fileContent = fs.readFileSync(abPath, {
    encoding: 'utf8',
  });
  return fileContent;
}
function getAbsolutePath(base, relative) {
  debugger;
  let ext = path.extname(base);
  if (ext && relative.length) {
    base = path.dirname(base);
  }
  let abPath = path.join(base, relative);
  if (!fs.existsSync(abPath)) {
    if (fs.existsSync(abPath + '.js')) {
      console.log(abPath + '.js');
      abPath += '.js';
    } else if (fs.existsSync(abPath + '/index.js')) {
      abPath += '/index.js';
    }
  } else {
    if (fs.existsSync(abPath + '.js')) {
      abPath += '.js';
    } else if (fs.existsSync(abPath + '/index.js')) {
      abPath += '/index.js';
    }
  }
  return abPath;
}
// console.log(getAbsolutePath('/users/apple/index.js', './modules.js'));

function getAst(fileContent) {
  return parse(fileContent, { sourceType: 'module' });
}

/**
 *
 *
 * @param {any} Program
 * @returns
 */
function getModuleOrPathMap(ast) {
  let node = ast.program;
  let importDeclarationList = node.body.filter(
    item => item.type === 'ImportDeclaration',
  );
  let modulelOrPathMap = importDeclarationList.reduce((acc, cur) => {
    let moduleOrPath = cur.source.value;
    cur.specifiers
      .filter(specifier => specifier.type === 'ImportDefaultSpecifier')
      .forEach(specifier => {
        acc[specifier.local.name] = moduleOrPath;
      });
    return acc;
  }, {});
  return modulelOrPathMap;
}

/**
 *
 *
 * @param {File} ast
 * @returns {StoreAstMap}
 */
function getFileDefinationAstMap(ast) {
  let program = ast.program;
  let storeAstMap = {};
  let variableDeclarationList = program.body.filter(
    item =>
      item.type === 'VariableDeclaration' && item.declarations.length === 1,
  );
  variableDeclarationList.forEach(varDeclation => {
    let firstDeclarator = varDeclation.declarations[0];
    if (firstDeclarator.init.type !== 'ObjectExpression') {
      return;
    }
    let id = firstDeclarator.id.name;
    storeAstMap[id] = firstDeclarator.init;
  });
  return storeAstMap;
}
/**
 * 辅助函数用来判断第二个参数传入的对象中的内容是否在a中都一样，如果一样返回true，否则返回false
 *
 * @param {object} a
 * @param {object} b
 * @returns
 */
function looksLike(a, b) {
  return (
    a &&
    b &&
    Object.keys(b).every(bKey => {
      const bVal = b[bKey];
      const aVal = a[bKey];
      if (typeof bVal === 'function') {
        return bVal(aVal);
      }
      return isPrimitive(bVal) ? bVal === aVal : looksLike(aVal, bVal);
    })
  );
}

/**
 * 判断一个对象是否是基本类型
 *
 * @param {any} val
 * @returns
 */
function isPrimitive(val) {
  return val == null || /^[sbn]/.test(typeof val);
}

module.exports = {
  getFileContent,
  getAst,
  getModuleOrPathMap,
  getFileDefinationAstMap,
  getAbsolutePath,
  looksLike,
};
